﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;

namespace Model
{
	public class YJKLine
	{
		public YJKLine(XYZ start, XYZ end)
		{
			this.line = YJKLineEx.YJKGetBound(start, end);
			this.startPoint = start;
			this.endPoint = end;
		}

		public YJKLine(Line line)
		{
			this.line = line;
			if (line.IsBound)
			{
				this.startPoint = line.GetEndPoint(0);
				this.endPoint = line.GetEndPoint(1);
				return;
			}
			this.isBound = false;
		}

		public XYZ StartPoint
		{
			get
			{
				return this.startPoint;
			}
		}

		public XYZ EndPoint
		{
			get
			{
				return this.endPoint;
			}
		}

		public void MakeUnBound()
		{
			this.isBound = false;
			this.line.MakeUnbound();
		}

		public bool IsBound
		{
			get
			{
				this.isBound = this.line.IsBound;
				return this.isBound;
			}
		}

		public Line Line
		{
			get
			{
				return this.line;
			}
		}

		public bool IsParallel(Line otherLine)
		{
			bool result = false;
			YJKLine hyline = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
			XYZ xyz = this.startPoint - this.endPoint;
			XYZ xyz2 = hyline.StartPoint - hyline.EndPoint;
			double num = xyz.AngleTo(xyz2);
			if (Math.Abs(num - Math.PI) < 0.0001 || num < 0.0001)
			{
				result = true;
			}
			return result;
		}

		public bool IsXYParallel(Line otherLine)
		{
			bool result = false;
			YJKLine hyline = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
			XYZ xyz = new XYZ(this.startPoint.X, this.startPoint.Y, 0.0) - new XYZ(this.endPoint.X, this.endPoint.Y, 0.0);
			XYZ xyz2 = new XYZ(hyline.StartPoint.X, hyline.StartPoint.Y, 0.0) - new XYZ(hyline.EndPoint.X, hyline.EndPoint.Y, 0.0);
			double num = xyz.AngleTo(xyz2);
			if (Math.Abs(num - Math.PI) < 0.0001 || num < 0.0001)
			{
				result = true;
			}
			return result;
		}

		public double GetDistance(Line otherLine)
		{
			double result = -1.0;
			if (this.IsParallel(otherLine))
			{
				YJKLine hyline = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
				hyline.MakeUnBound();
				result = hyline.Line.Distance(this.startPoint);
			}
			return result;
		}

		public double GetXYDistance(Line otherLine)
		{
			double result = -1.0;
			if (this.IsXYParallel(otherLine))
			{
				YJKLine hyline = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
				XYZ xyz = new XYZ(hyline.StartPoint.X, hyline.StartPoint.Y, 0.0);
				XYZ xyz2 = new XYZ(hyline.EndPoint.X, hyline.EndPoint.Y, 0.0);
				Line line = YJKLineEx.YJKGetBound(xyz, xyz2);
				line.MakeUnbound();
				XYZ xyz3 = new XYZ(this.startPoint.X, this.startPoint.Y, 0.0);
				result = line.Distance(xyz3);
			}
			return result;
		}

		public XYZ GetXYVector(Line otherLine)
		{
			XYZ xyz = new XYZ(0.0, 0.0, 0.0);
			if (this.IsXYParallel(otherLine))
			{
				YJKLine hyline = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
				XYZ xyz2 = new XYZ(hyline.StartPoint.X, hyline.StartPoint.Y, 0.0);
				XYZ xyz3 = new XYZ(hyline.EndPoint.X, hyline.EndPoint.Y, 0.0);
				Line line = YJKLineEx.YJKGetBound(new XYZ(this.startPoint.X, this.startPoint.Y, 0.0), new XYZ(this.endPoint.X, this.endPoint.Y, 0.0));
				line.MakeUnbound();
				XYZ xyz4 = xyz2 - xyz3;
				XYZ xyz5 = new XYZ(0.0, 0.0, 1.0);
				XYZ xyz6 = xyz4.CrossProduct(xyz5).Normalize() + xyz2;
				Line line2 = YJKLineEx.YJKGetBound(xyz2, xyz6);
				line2.MakeUnbound();
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				SetComparisonResult setComparisonResult = line.Intersect(line2, out intersectionResultArray);
				if (4 != (int)setComparisonResult && !intersectionResultArray.IsEmpty)
				{
					xyz = intersectionResultArray.get_Item(0).XYZPoint;
				}
				if (!xyz2.IsAlmostEqualTo(xyz))
				{
					xyz = (xyz - xyz2).Normalize();
				}
			}
			return xyz;
		}

		public XYZ GetVector(Line otherLine)
		{
			XYZ result = new XYZ(0.0, 0.0, 0.0);
			if (this.IsXYParallel(otherLine))
			{
				Line line = new YJKLine(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1)).Line;
				line.MakeUnbound();
				IntersectionResult intersectionResult = new IntersectionResult();
				intersectionResult = line.Project(this.startPoint);
				XYZ xyz = new XYZ();
				if (intersectionResult != null)
				{
					xyz = intersectionResult.XYZPoint;
				}
				if (xyz != null)
				{
					result = (this.startPoint - xyz).Normalize();
				}
			}
			return result;
		}

		public XYZ IntersectionPoint(Line otherLine)
		{
			XYZ result = new XYZ();
			result = null;
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			SetComparisonResult setComparisonResult = this.line.Intersect(otherLine, out intersectionResultArray);
			if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
			{
				result = intersectionResultArray.get_Item(0).XYZPoint;
			}
			return result;
		}

		public XYZ IntersectionPoint(Line otherLine, bool unBound)
		{
			XYZ result = new XYZ();
			result = null;
			Line line = YJKLineEx.YJKGetBound(this.startPoint, this.endPoint);
			line.MakeUnbound();
			Line line2 = YJKLineEx.YJKGetBound(otherLine.GetEndPoint(0), otherLine.GetEndPoint(1));
			line2.MakeUnbound();
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			SetComparisonResult setComparisonResult = line.Intersect(line2, out intersectionResultArray);
			if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
			{
				result = intersectionResultArray.get_Item(0).XYZPoint;
			}
			return result;
		}

		public bool IsPointOnLine(XYZ xyz)
		{
			bool result = false;
			if (Math.Abs(xyz.DistanceTo(this.startPoint) + xyz.DistanceTo(this.endPoint) - this.startPoint.DistanceTo(this.endPoint)) < 0.0001)
			{
				result = true;
			}
			return result;
		}

		public bool IsPointOnLineExtension(XYZ xyz)
		{
			bool result = false;
			if (Math.Abs(Math.Abs(xyz.DistanceTo(this.startPoint) - xyz.DistanceTo(this.endPoint)) - this.startPoint.DistanceTo(this.endPoint)) < 0.0001)
			{
				result = true;
			}
			return result;
		}

		public bool IsPointOnCurveLine(XYZ xyz)
		{
			bool result = false;
			if (this.IsPointOnLine(xyz) || this.IsPointOnLineExtension(xyz))
			{
				result = true;
			}
			return result;
		}

		public bool IsLineOnLine(Line otherLine)
		{
			bool result = false;
			if (this.IsPointOnCurveLine(otherLine.GetEndPoint(0)) && this.IsPointOnCurveLine(otherLine.GetEndPoint(1)))
			{
				result = true;
			}
			return result;
		}

		public XYZ GetProject(XYZ point)
		{
			IntersectionResult intersectionResult = new IntersectionResult();
			intersectionResult = this.line.Project(point);
			XYZ result = null;
			if (intersectionResult != null)
			{
				result = intersectionResult.XYZPoint;
			}
			return result;
		}

		public List<XYZ> GetLineXYZList(XYZ globalPoint, double distance)
		{
			List<XYZ> list = new List<XYZ>();
			XYZ item = (this.line.GetEndPoint(0) - this.line.GetEndPoint(1)).Normalize() * distance + globalPoint;
			XYZ item2 = -(this.line.GetEndPoint(0) - this.line.GetEndPoint(1)).Normalize() * distance + globalPoint;
			list.Add(item);
			list.Add(item2);
			return list;
		}

		private Line line;

		private bool isBound = true;

		private XYZ startPoint = new XYZ(0.0, 0.0, 0.0);

		private XYZ endPoint = new XYZ(0.0, 0.0, 0.0);
	}
}
